package main

import (
	"encoding/json"
	"fmt"
	"github.com/hyperledger/fabric/common/flogging"
	"github.com/hyperledger/fabric/core/chaincode/shim"
	pb "github.com/hyperledger/fabric/protos/peer"
	"strings"
)

var logger = flogging.MustGetLogger("cbsp")

//定义Chaincode结构体
type SimpleChaincode struct {
}

//Message结构体
type Message struct {
	Info   string `json:"info"`
	Digest string `json:"digest"`
	Dataid string `json:"dataid"`
}

//主函数调用
func main() {
	err := shim.Start(new(SimpleChaincode))
	if err != nil {
		fmt.Printf("Error starting Simple chaincode: %s", err)
	}
}

/**
 *
 *初始化
 */
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
	logger.Infof("simplechode Init")
	return shim.Success(nil)
}

/**
 *调用功能
 *
 */
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
	function, args := stub.GetFunctionAndParameters()
	logger.Infof("invoke is running function=%v ", function)

	// Handle different functions
	if function == "savetocbsp" { //存储公钥
		return t.saveToCbsp(stub, args)
	} else if function == "querydatabyid" { //用户注册
		return t.queryDataById(stub, args)
	} else if function == "checkdata" { //
		return t.checkData(stub, args)
	} else if function == "checkandquerydata" { //
		return t.checkAndQueryData(stub, args)
	}
	logger.Infof("invoke did not find func:%v ", function) //error
	return shim.Error("Received unknown function invocation")
}

/**
 *保存数据到CAP4J区块链防伪平台
 *参数:
 *key string :数据防伪摘要
 *dataID string :数据对应的业务唯一编号
 *infoJsonObject string json :本次保存数据的属性信息
 */
func (t *SimpleChaincode) saveToCbsp(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	var err error
	var key, dataID, infoJsonObject string
	var jsonResp string
	jsonError := "{\"status\":\"Error\"}"
	logger.Infof("---saveToCbsp begin---")
	if len(args) != 3 {
		jsonResp = "Incorrect number of arguments. Expecting 3"
		logger.Infof(jsonResp)
		return shim.Success([]byte(jsonError))
	}
	if len(args[0]) <= 0 {
		jsonResp = "1st argument must be a non-empty string"
		logger.Infof(jsonResp)
		return shim.Success([]byte(jsonError))
	}
	if len(args[1]) <= 0 {
		jsonResp = "2nd argument must be a non-empty string"
		logger.Infof(jsonResp)
		return shim.Success([]byte(jsonError))
	}
	if len(args[2]) <= 0 {
		jsonResp = "3rd argument must be a non-empty string"
		logger.Infof(jsonResp)
		return shim.Success([]byte(jsonError))
	}

	key = args[0]
	dataID = args[1]
	infoJsonObject = args[2]
	logger.Infof("arguments:key=%s,dataID=%s,infoJsonObject=%s", key, dataID, infoJsonObject)

	m := Message{infoJsonObject, key, dataID}

	//保存交易记录到队列
	infoAsBytes, err := stub.GetState(dataID)
	//logger.Infof("infoAsBytes  is %v", infoAsBytes)
	logger.Infof("infoAsBytesObj  is %v", string(infoAsBytes))
	if err != nil {
		jsonResp = "Failed to get state for: " + dataID
		logger.Infof(jsonResp)
		return shim.Success([]byte(jsonError))
	}
	logger.Infof("info GetState  is ok")
	var infoJsonObjectArr []Message
	if infoAsBytes != nil {
		err = json.Unmarshal(infoAsBytes, &infoJsonObjectArr)
		logger.Infof("infoJsonObjectArr  is %v,err=%v", infoJsonObjectArr, err)
		if err != nil {
			return shim.Success([]byte(jsonError))
		}
	}
	logger.Infof("infoJsonObjectArr  is %v", infoJsonObjectArr)
	logger.Infof("infoJsonObjectArr len is %v", len(infoJsonObjectArr))

	infoJsonObjectArr = append(infoJsonObjectArr, m)
	logger.Infof("now infoJsonObjectArr  is %v", infoJsonObjectArr)
	infoJSONasBytes, err := json.Marshal(infoJsonObjectArr)
	if err != nil {
		return shim.Success([]byte(jsonError))
	}
	//logger.Infof("infoJSONasBytes=%v", infoJSONasBytes)
	logger.Infof("infoJSONasBytesObj=%v", string(infoJSONasBytes))
	// === Save info to state ===
	err = stub.PutState(dataID, infoJSONasBytes)
	if err != nil {
		return shim.Success([]byte(jsonError))
	}
	logger.Infof("infoJsonObjectArr save success in ledger, len is %v", len(infoJsonObjectArr))

	//保存摘要与业务id的键值对
	splitKey := strings.Split(key, ",")
	for i := range splitKey {
		sKey := splitKey[i]
		err = stub.PutState(sKey, []byte(dataID))
		if err != nil {
			return shim.Success([]byte(jsonError))
		}
	}

	logger.Infof("---saveToCbsp end---")
	return shim.Success(nil)
}

/**
 *查询
 *参数:
 * dataID
 */
func (t *SimpleChaincode) queryDataById(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	var err error
	var dataID, jsonResp string
	var valAsbytes []byte
	jsonError := "{\"status\":\"Error \"}"
	logger.Infof("---queryDataById begin---")
	if len(args) != 1 {
		logger.Infof("Incorrect number of arguments. Expecting 1")
		return shim.Success([]byte(jsonError))
	}

	if len(args[0]) <= 0 {
		logger.Infof("argument must be a non-empty string")
		return shim.Success([]byte(jsonError))
	}

	dataID = args[0] //

	valAsbytes, err = stub.GetState(dataID) //get the info from chaincode state
	if err != nil {
		jsonResp = "{\"Error\":\"Failed to get state for " + dataID + " \"}"
		logger.Infof(jsonResp)
		return shim.Success([]byte(jsonError))
	}
	if valAsbytes == nil {
		jsonResp = "{\"Error\":\"Info does not exist: " + dataID + " \"}"
		logger.Infof(jsonResp)
		return shim.Success([]byte(jsonError))
	}
	//logger.Infof("valAsbytes %v", valAsbytes)
	logger.Infof("valAsbytes %v", string(valAsbytes))
	logger.Infof("---queryDataById end---")
	return shim.Success(valAsbytes)
}

/**
 *上传数据摘要 到CAP4J区块链防伪平台
 *参数：
 * key string 参数防伪摘要
 */
func (t *SimpleChaincode) checkData(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	var err error
	var key, jsonResp string
	jsonError := "{\"status\":\"Error\"}"
	jsonOK := "{\"status\":\"OK\"}"
	logger.Infof("---checkData begin---")
	if len(args) != 1 {
		logger.Infof("Incorrect number of arguments. Expecting 1")
		return shim.Success([]byte(jsonError))
	}

	if len(args[0]) <= 0 {
		logger.Infof("argument must be a non-empty string")
		return shim.Success([]byte(jsonError))
	}

	key = args[0] //

	dataIDAsbytes, err := stub.GetState(key) //get the info from chaincode state
	if err != nil {
		logger.Infof("{\"Error\":\"Failed to get state for " + key + "\"}")
		return shim.Success([]byte(jsonError))
	} else if dataIDAsbytes == nil {
		logger.Infof("{\"Error\":\"dataID of key %s does not exist: " + key + "\"}")
		return shim.Success([]byte(jsonError))
	}

	dataID := string(dataIDAsbytes)
	logger.Infof("digest %s对应的dataID为%s", key, dataID)

	infoJsonObjectAsbytes, err := stub.GetState(dataID) //get the info from chaincode state
	if err != nil {
		jsonResp = "{\"Error\":\"Failed to get state for " + dataID + "\"}"
		logger.Infof(jsonResp)
		return shim.Success([]byte(jsonError))
	} else if infoJsonObjectAsbytes == nil {
		jsonResp = "{\"Error\":\"infoJsonObjectAsbytes of dataID %s does not exist: " + dataID + "\"}"
		logger.Infof(jsonResp)
		return shim.Success([]byte(jsonError))
	}

	var infoJsonObjectArr []Message
	err = json.Unmarshal(infoJsonObjectAsbytes, &infoJsonObjectArr)
	if err != nil {
		return shim.Success([]byte(jsonError))
	}
	infoJsonObjectArrSize := len(infoJsonObjectArr)
	logger.Infof("infoJsonObjectArr,len is %v", infoJsonObjectArrSize)
	if 0 == infoJsonObjectArrSize {
		jsonResp = "{\"Error\":\"infoJsonObjectArr len is 0 \"}"
		logger.Infof(jsonResp)
		return shim.Success([]byte(jsonError))
	}

	newestInfoJsonObject := infoJsonObjectArr[infoJsonObjectArrSize-1]
	logger.Infof("newestInfoJsonObject %v", newestInfoJsonObject)

	digest := newestInfoJsonObject.Digest //m.Digest
	logger.Infof("digest= %v,key=%v", digest, key)

	if strings.Contains(digest, key) {
		return shim.Success([]byte(jsonOK))
	}
	//if strings.EqualFold(digest, key) {
	//	return shim.Success([]byte(jsonOK))
	//}

	logger.Infof("---checkData end---")
	return shim.Success([]byte(jsonError))
}

/**
 *
 *
 */
func (t *SimpleChaincode) checkAndQueryData(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	var err error
	var key, jsonResp string
	jsonError := "{\"status\":\"Error\"}"
	//jsonOK := "{\"status\":\"OK\"}"

	logger.Infof("---checkAndQueryData begin---")
	if len(args) != 1 {
		logger.Infof("Incorrect number of arguments. Expecting 1")
		return shim.Success([]byte(jsonError))
	}

	if len(args[0]) <= 0 {
		logger.Infof("argument must be a non-empty string")
		return shim.Success([]byte(jsonError))
	}

	key = args[0] //

	//通过摘要值查询dataID
	dataIDAsbytes, err := stub.GetState(key) //get the info from chaincode state
	if err != nil {
		jsonResp = "{\"Error\":\"Failed to get state for " + key + "\"}"
		logger.Infof(jsonResp)
		return shim.Success([]byte(jsonError))
	}
	if dataIDAsbytes == nil {
		jsonResp = "{\"Error\":\"dataID of key %s does not exist: " + key + "\"}"
		logger.Infof(jsonResp)
		return shim.Success([]byte(jsonError))
	}

	dataID := string(dataIDAsbytes)
	logger.Infof("digest %s对应的dataID为%s", key, dataID)

	infoJsonObjectAsbytes, err := stub.GetState(dataID) //get the info from chaincode state
	if err != nil {
		jsonResp = "{\"Error\":\"Failed to get state for " + dataID + "\"}"
		logger.Infof(jsonResp)
		return shim.Success([]byte(jsonError))
	} else if infoJsonObjectAsbytes == nil {
		jsonResp = "{\"Error\":\"infoJsonObjectAsbytes of dataID %s does not exist: " + dataID + "\"}"
		logger.Infof(jsonResp)
		return shim.Success([]byte(jsonError))
	}

	var infoJsonObjectArr []Message
	err = json.Unmarshal(infoJsonObjectAsbytes, &infoJsonObjectArr)
	if err != nil {
		return shim.Success([]byte(jsonError))
	}
	infoJsonObjectArrSize := len(infoJsonObjectArr)
	logger.Infof("infoJsonObjectArr,len is %v", infoJsonObjectArrSize)
	if 0 == infoJsonObjectArrSize {
		jsonResp = "{\"Error\":\"infoJsonObjectArr len is 0 \"}"
		logger.Infof(jsonResp)
		return shim.Success([]byte(jsonError))
	}

	newestInfoJsonObject := infoJsonObjectArr[infoJsonObjectArrSize-1]
	logger.Infof("newestInfoJsonObject %v", newestInfoJsonObject)

	digest := newestInfoJsonObject.Digest //m.Digest
	logger.Infof("digest= %v,key=%v", digest, key)

	if strings.Contains(digest, key) {
		return shim.Success(infoJsonObjectAsbytes)
	}

	//	if strings.EqualFold(digest, key) {
	//		return shim.Success(infoJsonObjectAsbytes)
	//	}

	logger.Infof("---checkAndQueryData end---")
	return shim.Success([]byte(jsonError))
}
